<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>损失函数展开：一步步给高中生看</title>
    <style>
        body{
            font-family: "Segoe UI",Arial,Helvetica,sans-serif;
            background:#fafafa;
            margin:0;
            padding:30px;
            color:#222;
        }
        h1{
            text-align:center;
            margin-bottom:10px;
            font-size:28px;
        }
        .subtitle{
            text-align:center;
            margin-bottom:30px;
            color:#666;
            font-size:16px;
        }
        #main{
            max-width:1000px;
            margin:auto;
            background:#fff;
            border-radius:10px;
            box-shadow:0 2px 10px rgba(0,0,0,.08);
            padding:30px 40px;
            display:flex;
            gap:40px;
        }
        /* 左侧公式区 */
        #left{
            flex:1;
            display:flex;
            flex-direction:column;
            gap:20px;
        }
        .step-box{
            border:1px solid #e0e0e0;
            border-radius:8px;
            padding:20px;
            opacity:0;
            transform:translateY(15px);
            transition:all .5s ease;
        }
        .step-box.active{
            opacity:1;
            transform:none;
        }
        .step-title{
            font-size:18px;
            font-weight:bold;
            margin-bottom:10px;
            color:#3498db;
        }
        .formula{
            font-size:22px;
            margin:10px 0;
            line-height:1.8;
            font-family:"Times New Roman",serif;
        }
        .formula .item{
            display:inline-block;
            padding:3px 8px;
            border-radius:4px;
            margin:0 2px;
            transition:background .3s;
            cursor:pointer;
        }
        .formula .item.from-y{
            background:#ffecb3;
        }
        .formula .item.from-beta{
            background:#c8e6c9;
        }
        .formula .item.from-mix{
            background:#bbdefb;
        }
        /* 右侧定理区 */
        #right{
            width:300px;
            border-left:2px solid #e0e0e0;
            padding-left:30px;
        }
        #right h3{
            margin-top:0;
            font-size:20px;
            color:#2c3e50;
        }
        .thm{
            margin-bottom:20px;
            font-size:15px;
            line-height:1.6;
            color:#444;
        }
        .thm.on{
            background:#f1f8fe;
            border-left:4px solid #3498db;
            padding:10px;
            border-radius:4px;
        }
        .thm-name{
            font-weight:bold;
            margin-bottom:4px;
        }
        /* 底部双框 */
        #bottom{
            max-width:1000px;
            margin:20px auto 0;
            display:flex;
            gap:20px;
        }
        #explain{
            flex:1;
            background:#f5f5f5;
            border-radius:8px;
            padding:20px;
            font-size:16px;
            line-height:1.7;
            min-height:100px;
        }
        #explain .emph{
            color:#d32f2f;
            font-weight:bold;
        }
        #itemDerive{
            flex:1;
            background:#fff8e1;
            border-radius:8px;
            padding:20px;
            font-size:16px;
            line-height:1.7;
            border:1px solid #ffd54f;
        }
        /* 控制按钮 */
        #controls{
            text-align:center;
            margin-top:20px;
        }
        button{
            background:#3498db;
            color:#fff;
            border:none;
            padding:10px 24px;
            margin:0 6px;
            border-radius:6px;
            font-size:16px;
            cursor:pointer;
            transition:background .3s;
        }
        button:hover{background:#2980b9;}
        button:disabled{background:#bbb;cursor:not-allowed;}
    </style>
</head>
<body>
    <h1>损失函数展开：一步步给高中生看</h1>
    <div class="subtitle">—— 不跳步，连合并同类项都拆给你 ——</div>

    <div id="main">
        <div id="left">
            <!-- 步骤0 原始式 -->
            <div class="step-box" id="b0">
                <div class="step-title">第0步：原始损失函数</div>
                <div class="formula">
                    L(β) = (<span class="item from-y">y</span> − <span class="item from-beta">Xβ</span>)<sup>T</sup>(<span class="item from-y">y</span> − <span class="item from-beta">Xβ</span>)
                </div>
            </div>

            <!-- 步骤1 展开转置 -->
            <div class="step-box" id="b1">
                <div class="step-title">第1步：把括号转置展开</div>
                <div class="formula">
                    L(β) = (<span class="item from-y">y<sup>T</sup></span> − <span class="item from-beta">β<sup>T</sup>X<sup>T</sup></span>) (<span class="item from-y">y</span> − <span class="item from-beta">Xβ</span>)
                </div>
            </div>

            <!-- 步骤2 四项乘开 -->
            <div class="step-box" id="b2">
                <div class="step-title">第2步：四项全部乘开</div>
                <div class="formula">
                    L(β) = <span class="item from-y">y<sup>T</sup>y</span> − <span class="item from-mix">y<sup>T</sup>Xβ</span> − <span class="item from-mix">β<sup>T</sup>X<sup>T</sup>y</span> + <span class="item from-beta">β<sup>T</sup>X<sup>T</sup>Xβ</span>
                </div>
            </div>

            <!-- 步骤3+4 合并 -->
            <div class="step-box" id="b3">
                <div class="step-title">第3步：合并同类项</div>
                <div class="formula">
                    L(β) = <span class="item from-y">y<sup>T</sup>y</span> − 2<span class="item from-mix">β<sup>T</sup>X<sup>T</sup>y</span> + <span class="item from-beta">β<sup>T</sup>X<sup>T</sup>Xβ</span>
                </div>
            </div>
        </div>

        <div id="right">
            <h3>所用定理</h3>
            <div class="thm" id="t1">
                <div class="thm-name">矩阵转置性质</div>
                <div>(A − B)<sup>T</sup> = A<sup>T</sup> − B<sup>T</sup></div>
            </div>
            <div class="thm" id="t2">
                <div class="thm-name">乘法分配律</div>
                <div>左：C(A−B) = CA − CB<br>右：(A−B)C = AC − BC</div>
            </div>
            <div class="thm" id="t3">
                <div class="thm-name">“形状”检查</div>
                <div>y<sup>T</sup> 是1×n，X是n×p，β是p×1 → 结果1×1</div>
            </div>
            <div class="thm" id="t4">
                <div class="thm-name">标量自转置</div>
                <div>一个数等于自己的转置：x = x<sup>T</sup></div>
            </div>
            <div class="thm" id="t5">
                <div class="thm-name">合并同类项</div>
                <div>−a − a = −2a</div>
            </div>
        </div>
    </div>

    <!-- 底部双框 -->
    <div id="bottom">
        <div id="explain">
            点击“下一步”开始，每一步都会在这里用<span class="emph">高中生语言</span>告诉你发生了什么。
        </div>
        <div id="itemDerive">
            把鼠标悬停到彩色项上，这里会实时显示<span class="emph">它从哪一步变过来</span>。
        </div>
    </div>

    <!-- 控制按钮 -->
    <div id="controls">
        <button id="btnPrev" onclick="move(-1)">上一步</button>
        <button id="btnNext" onclick="move(1)">下一步</button>
        <button onclick="reset()">重置</button>
    </div>

    <script>
        const total=4;
        let cur=0;
        const boxes=document.querySelectorAll('.step-box');
        const thms=document.querySelectorAll('.thm');
        const exp=document.getElementById('explain');
        const itemBox=document.getElementById('itemDerive');
        const btnPrev=document.getElementById('btnPrev');
        const btnNext=document.getElementById('btnNext');

        // 每一步对应的思路解释
        const expText=[
            "原始式子：把预测值和真实值的差先整体转置，再乘自己。",
            "把括号打开：记住‘差的转置=转置的差’，所以(y−Xβ)ᵀ=yᵀ−βᵀXᵀ。",
            "现在用‘乘法分配律’把两项×两项展开成四项，不跳步！",
            "关键：先别急着合并，看看中间两项长啥样——用‘形状检查’发现它们都是1×1的数；因为它们是‘标量’，所以yᵀXβ = (yᵀXβ)ᵀ = βᵀXᵀy，这就是‘标量自转置’；现在可以把−yᵀXβ 和 −βᵀXᵀy 合并成 −2βᵀXᵀy，完成！"
        ];

        // 悬停提示库
        const hoverMap={
            "yTy":"【y<sup>T</sup>y】<br>来自第2步第一项，直接保留，没有变化。",
            "yTXβ":"【y<sup>T</sup>Xβ】<br>第2步第二项；因为它是1×1标量，所以y<sup>T</sup>Xβ = (y<sup>T</sup>Xβ)<sup>T</sup> = β<sup>T</sup>X<sup>T</sup>y。",
            "βTXTy":"【β<sup>T</sup>X<sup>T</sup>y】<br>第2步第三项；同时它也是y<sup>T</sup>Xβ的转置形式，于是两项可以合并。",
            "βTXTXβ":"【β<sup>T</sup>X<sup>T</sup>Xβ】<br>第2步第四项，直接保留。",
            "2βTXTy":"【−2β<sup>T</sup>X<sup>T</sup>y】<br>合并过程：<br>−y<sup>T</sup>Xβ − β<sup>T</sup>X<sup>T</sup>y = −β<sup>T</sup>X<sup>T</sup>y − β<sup>T</sup>X<sup>T</sup>y = −2β<sup>T</sup>X<sup>T</sup>y"
        };

        function render(){
            // 步骤盒
            boxes.forEach((b,i)=>b.classList.toggle('active',i<=cur));
            // 定理高亮
            thms.forEach((t,i)=>t.classList.toggle('on',i<=cur));
            // 解释文字
            exp.innerHTML=expText[cur];
            // 按钮
            btnPrev.disabled=cur===0;
            btnNext.disabled=cur===total;
        }
        function move(d){
            const n=cur+d;
            if(n>=0&&n<=total){cur=n;render();}
        }
        function reset(){cur=0;render();}

        // 悬停事件
        document.querySelectorAll('.item').forEach(item=>{
            item.onmouseenter=e=>{
                const key=e.target.textContent.replace(/[^a-zA-Zβ]/g,''); // 简单取key
                let html="";
                if(key==="yTy")html=hoverMap["yTy"];
                if(key==="yTXβ")html=hoverMap["yTXβ"];
                if(key==="βTXTy")html=hoverMap["βTXTy"];
                if(key==="βTXTXβ")html=hoverMap["βTXTXβ"];
                if(key==="2βTXTy")html=hoverMap["2βTXTy"];
                itemBox.innerHTML=html||"暂无提示";
            };
            item.onmouseleave=()=>{
                itemBox.innerHTML="把鼠标悬停到彩色项上，这里会实时显示<span class='emph'>它从哪一步变过来</span>。";
            };
        });

        render();
    </script>
</body>
</html>